﻿using FR.SAFTAnalyser.Model.EF;
using FR.SAFTAnalyser.ViewModels.Pane;
using MEFedMVVM.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FR.SAFTAnalyser.ViewModels.Tools
{
    public class SaveToBDViewModel : ToolViewModel, ITool
    {
        public SaveToBDViewModel()
            : base("Guardar BD")
        {
            if (!Designer.IsInDesignMode)
            {
                this.ConnectionString = Workspace.Workspace.Instance.Config.ConnectionString;
                this.ReCreateBD = true;

                //commands
                this.SaveCommand = new Cinch.SimpleCommand<object, object>(CanSave, DoSave);
            }
        }

        #region Binding properties
        double currentStep;
        public double CurrentStep
        {
            get { return currentStep; }
            set
            {
                currentStep = value;
                NotifyPropertyChanged(Cinch.ObservableHelper.CreateArgs<SaveToBDViewModel>(c => c.CurrentStep));
            }
        }

        bool isWorking;
        public bool IsWorking
        {
            get { return isWorking; }
            set
            {
                isWorking = value;
                NotifyPropertyChanged(Cinch.ObservableHelper.CreateArgs<SaveToBDViewModel>(c => c.IsWorking));
            }
        }

        private string connectionString;
        public string ConnectionString
        {
            get { return connectionString; }
            set
            {
                connectionString = value;
                Workspace.Workspace.Instance.Config.ConnectionString = connectionString;
                NotifyPropertyChanged(Cinch.ObservableHelper.CreateArgs<SaveToBDViewModel>(c => c.ConnectionString));
            }
        }

        private bool reCreateBD;
        public bool ReCreateBD
        {
            get { return reCreateBD; }
            set
            {
                reCreateBD = value;
                NotifyPropertyChanged(Cinch.ObservableHelper.CreateArgs<SaveToBDViewModel>(c => c.ReCreateBD));
            }
        }

        StringBuilder messages;
        public string Messages
        {
            get
            {
                if (messages == null) messages = new StringBuilder();
                return messages.ToString();
            }
            set
            {
                messages.AppendFormat("{0:yyyy/MM/dd HH:mm:ss}: {1}{2}", DateTime.Now, value, Environment.NewLine);
                NotifyPropertyChanged(Cinch.ObservableHelper.CreateArgs<SaveToBDViewModel>(c => c.Messages));
            }
        }
        #endregion

        #region Commands
        public Cinch.SimpleCommand<object, object> SaveCommand { get; set; }

        BackgroundWorker bw = null;
        private void DoSave(object args)
        {
            bw = new BackgroundWorker();
            bw.DoWork += bw_DoWork;
            bw.ProgressChanged += bw_ProgressChanged;
            bw.RunWorkerCompleted += bw_RunWorkerCompleted;
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;

            bw.RunWorkerAsync();
        }

        private bool CanSave(object args)
        {
            return string.IsNullOrEmpty(this.ConnectionString) == false && SAFTAnalyser.SAFT.SaftAnalyser.Instance.SaftFile != null;
        }

        #endregion

        #region BackgroundWorker
        SaftModelContext context = null;
        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.Messages = "Processo finalizado";
            this.CurrentStep = 100;
        }

        void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.Messages = e.UserState.ToString();
            this.CurrentStep = e.ProgressPercentage;
        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                this.IsWorking = true;
                Model.AuditFile auditFile = SAFTAnalyser.SAFT.SaftAnalyser.Instance.SaftFile;

                int passo = 1, totalPassos = 2;

                using (context = new SaftModelContext(ConnectionString))
                {
                    //inicializar o nº total de passos
                    totalPassos += this.ReCreateBD ? 1 : 0;
                    totalPassos += context.Database.Exists() ? 1 : 0;
                    totalPassos += auditFile.MasterFiles != null ? 3 : 0;
                    totalPassos += auditFile.SourceDocuments != null ? 2 : 0;

                    bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "Processo iniciado");

                    if (this.ReCreateBD)
                    {
                        context.Database.Delete();
                        bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "BD apagada");
                    }

                    if (context.Database.CreateIfNotExists())
                        bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "BD Criada");

                    EntitiesMaper.MapHeader(auditFile.Header, context);
                    bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "Cabeçalho guardado");

                    if (auditFile.MasterFiles != null)
                    {
                        if (auditFile.MasterFiles.Product != null)
                            EntitiesMaper.MapProducts(auditFile.MasterFiles.Product, context);
                        bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "Produtos guardados");

                        if (auditFile.MasterFiles.Supplier != null)
                            EntitiesMaper.MapSuppliers(auditFile.MasterFiles.Supplier, context);
                        bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "Fornecedores guardados");

                        if (auditFile.MasterFiles.Customer != null)
                            EntitiesMaper.MapCustomers(auditFile.MasterFiles.Customer, context);
                        bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "Clientes guardados");
                    }

                    if (auditFile.SourceDocuments != null)
                    {
                        if (auditFile.SourceDocuments.SalesInvoices != null)
                            EntitiesMaper.MapSalesInvoices(auditFile.SourceDocuments.SalesInvoices, context, !this.ReCreateBD);
                        bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "Resumo Documentos guardado");

                        if (auditFile.SourceDocuments.SalesInvoices.Invoice != null)
                            EntitiesMaper.MapInvoices(auditFile.SourceDocuments.SalesInvoices.Invoice, context);
                        bw.ReportProgress(CalculaPercentagem(totalPassos, ref passo), "Documentos guardados");
                    }
                }

            }
            catch (Exception ex)
            {
                StringBuilder sb = new StringBuilder(ex.Message);

                Exception inner = ex.InnerException;
                while (inner != null)
                {
                    sb.AppendLine(inner.Message);
                    inner = inner.InnerException;
                }

                bw.ReportProgress(0, sb.ToString());
            }
        }

        private int CalculaPercentagem(int totalPassos, ref int passo)
        {
            passo++;
            return (int)((passo / (totalPassos*1.0)) * 100);
        }
        #endregion

        #region ITool interface
        PaneLocation preferredLocation = new PaneLocation { Location = PaneLocation.LEFT };
        public PaneLocation PreferredLocation
        {
            get { return preferredLocation; }
            set { preferredLocation = value; }
        }

        bool isAutoHidden = true;
        public bool IsAutoHidden
        {
            get { return isAutoHidden; }
            set { isAutoHidden = value; }
        }
        #endregion
    }
}
